﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;

namespace BaiduRefresher
{
    public class UrlAccesser
    {

        #region 属性及构造函数
        //private ManualResetEvent manualEvent;
        private string hostName = null;
        private bool connected=false;
        private int? port=null;
        private string url;
        private int failtimes=0;
        private int timeout = 1000 * 10;
        public int Timeout
        {
            get { return timeout; }
            set { timeout = value; }
        }
        public bool Connected
        {
            get { return connected; }
        }
        public string HostName
        {
            get { return hostName; }
            set { hostName = value; }
        }
        public int? Port
        {
            get { return port; }
            set { port = value; }
        }
        public string Url
        {
            get { return url; }
            set { url = value; }
        }
        public int Failtimes
        {
            get { return failtimes; }
            set { failtimes = value; }
        }
        public UrlAccesser(string hostName, int? port, string url)
        {
            this.hostName = hostName;
            this.port = port;
            this.url = url;            
            //manualEvent = new ManualResetEvent(false);
        }
        public UrlAccesser(string url)
        {           
            this.url = url;            
            //manualEvent = new ManualResetEvent(false);
        }
        public UrlAccesser(string hostName, int? port, string url,int timeout)
        {
            this.hostName = hostName;
            this.port = port;
            this.url = url;
            this.timeout = timeout;
            //manualEvent = new ManualResetEvent(false);
        }
        public UrlAccesser(string url,int timeout)
        {
            this.url = url;
            this.timeout = timeout;
            //manualEvent = new ManualResetEvent(false);
        }

        #endregion

        public void AccessByLocal()
        {
            AccessUrl(null, null, this.url);
        }
        public void AccessByProxy()
        {
            AccessUrl(this.hostName, this.port, this.url);
        }
        public void Access()
        {
            if (hostName == null || port == null)
            {
                AccessByLocal();
            }
            else
            {
                AccessByProxy();
            }
        }
        private void AccessUrl(string host, int? port, string url)
        {
            WebProxy proxy = null;
            HttpWebRequest request = null;
            HttpWebResponse response = null;
            if (!(host == null || port == null))
            {
                try
                {
                    proxy = new WebProxy(host, Convert.ToInt32(port));
                }
                catch
                {
                    connected = false;
                    failtimes++;
                    return;
                }

            }
            //string url = //"http://captcha.qq.com/getimage?aid=3000801&0.43878429697395826";
            //    "http://hi.baidu.com/天之幻都";
            try
            {
                request = (HttpWebRequest)WebRequest.Create(url);
                request.Timeout = timeout;
                if (proxy != null)
                {
                    request.Proxy = proxy;
                }
                request.CookieContainer = new CookieContainer();
                response = (HttpWebResponse)request.GetResponse();
                connected = true;
                failtimes = 0;
            }
            catch (Exception ex)
            {
                connected = false;
                failtimes++;
            }
            finally
            {
                if (request != null)
                {
                    request.Abort();
                }
                if (response != null)
                {
                    response.Close();
                }
            }
        }
        private void AccessUrl(string url)
        {
            AccessUrl(null, null, url);
        }
    }

    public class UrlAccesserThreadState
    {
        private UrlAccesser urlAccesser;
        private AutoResetEvent autoEvent;

        public UrlAccesser UrlAccesser
        {
            get { return urlAccesser; }
            set { urlAccesser = value; }
        }

        public AutoResetEvent AutoEvent
        {
            get { return autoEvent; }
            set { autoEvent = value; }
        }

        public UrlAccesserThreadState(UrlAccesser urlAccesser, AutoResetEvent autoEvent)
        {
            this.urlAccesser = urlAccesser;
            this.autoEvent = autoEvent;
        }
    }

    public class UrlAccesserManager
    {
        #region 属性和构造函数
        private List<string> proxys;
        /// <summary>
        /// 字符串格式：IP:Port
        /// </summary>
        public List<string> Proxys
        {
            get { return proxys; }
            set { proxys = value; }
        }
        private int maxThread;
        /// <summary>
        /// 最大工作线程：25
        /// </summary>
        public int MaxThread
        {
            get { return maxThread; }
            set
            {
                if (value > 25)
                    maxThread = 25;
                else
                    maxThread = value;
            }
        }
        private string url;
        public string Url
        {
            get { return url; }
            set { url = value; }
        }
        private int accessTimes;
        public int AccessTimes
        {
            get { return accessTimes; }
            //set { accessTimes = value; }
        }
        private int timeout;

        public int Timeout
        {
            get { return timeout; }
            set { timeout = value; }
        }
        List<UrlAccesser> Accessers = new List<UrlAccesser>();
        private int availableAc;

        public int AvailableAc
        {
            get { return Accessers.Count; }
        }
        public UrlAccesserManager(List<string> proxys, string url,int timeout)
        {
            this.proxys = proxys;
            Accessers.Add(new UrlAccesser("http://hi.baidu.com/天之幻都"));
            Accessers.Add(new UrlAccesser(url,timeout * 1000));
            for (int i = 0; i < this.proxys.Count;i++ )
            {
                string[] curProxy = proxys[i].Split(':');
                UrlAccesser accesser = new UrlAccesser(curProxy[0], Convert.ToInt32(curProxy[1]), url,timeout * 1000);
                Accessers.Add(accesser);
            }
            this.url = url;
            maxThread = 25;
        }
        public UrlAccesserManager(string url)
        {
            this.proxys = null;
            Accessers.Add(new UrlAccesser("http://hi.baidu.com/天之幻都"));
            Accessers.Add(new UrlAccesser(url));
            this.url = url;
            maxThread = 25;
        }


        #endregion

        /// <summary>
        /// 开始访问
        /// </summary>
        /// <returns></returns>
        public void Start()
        {
            CheckFail();
            WaitCallback callBack = new WaitCallback(ThreadWork);
            ThreadPool.SetMaxThreads(maxThread, maxThread + 10);
            int runingThread = 0;
            int allThread = Accessers.Count;
            int needThread = (allThread - runingThread) > maxThread ? maxThread : (allThread - runingThread);
            AutoResetEvent[] autoEvents = new AutoResetEvent[needThread];
            for (int i = 0; i < needThread; i++)
            {
                UrlAccesser accesser = Accessers[runingThread];
                autoEvents[i] = new AutoResetEvent(false);
                UrlAccesserThreadState state = new UrlAccesserThreadState(accesser, autoEvents[i]);
                ThreadPool.QueueUserWorkItem(callBack, state);
                runingThread++;
            }
            while (runingThread < allThread)
            {
                int index = WaitHandle.WaitAny(autoEvents);
                UrlAccesser accesser = Accessers[runingThread];
                autoEvents[index] = new AutoResetEvent(false);
                UrlAccesserThreadState state = new UrlAccesserThreadState(accesser, autoEvents[index]);
                ThreadPool.QueueUserWorkItem(callBack, state);
                runingThread++;
            }
            WaitHandle.WaitAll(autoEvents, 1000 * 10);
            foreach (UrlAccesser ua in Accessers)
            {
                if (ua.Connected)
                {
                    accessTimes++;
                }                
            }
            if (accessTimes > 1)
            {
                accessTimes--;
            }
        }
        private void CheckFail()
        {
            for (int i = 0; i < Accessers.Count; i++)
            {
                if (Accessers[i].Failtimes == 5)
                {
                    Accessers.RemoveAt(i);
                    i--;
                    continue;
                }
            }
        }
        private void ThreadWork(object state)
        {
            ((UrlAccesserThreadState)state).UrlAccesser.Access();
            ((UrlAccesserThreadState)state).AutoEvent.Set();
        }

    }
}
